package com.hhxyjsj.plugin;

import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.sql.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.Timer;

import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

/**
 * 打印inser、update以及select语句的SQL及参数
 * 
 * @author hhxyj
 *
 */
@Intercepts({@Signature(
			  type= Executor.class,
			  method = "update",
			  args = {MappedStatement.class,Object.class}),
			  
			@Signature(
			  type = Executor.class, 
			  method = "query", 
			  args = {MappedStatement.class, Object.class, RowBounds.class,ResultHandler.class })})
public class SQLPrintPlugin implements Interceptor {

	/**
	 * 存放java基本类型的class名称
	 */
	private static Set<String> basicTypeSet = new HashSet<String>();
	
	static{
		basicTypeSet.add(Character.class.getName());
		basicTypeSet.add(String.class.getName());
		
		basicTypeSet.add(Byte.class.getName());
		basicTypeSet.add(Short.class.getName());
		basicTypeSet.add(Integer.class.getName());
		basicTypeSet.add(Long.class.getName());
		basicTypeSet.add(Float.class.getName());
		basicTypeSet.add(Double.class.getName());
		
		basicTypeSet.add(Boolean.class.getName());
		
		basicTypeSet.add(Date.class.getName());
		basicTypeSet.add(Timer.class.getName());

		basicTypeSet.add(BigDecimal.class.getName());
	}
	
	@SuppressWarnings("rawtypes")
	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		Object[] args = invocation.getArgs();
		BoundSql boundSql = ((MappedStatement) args[0]).getSqlSource().getBoundSql(args[1]);
		
		System.out.println("sql语句:" + boundSql.getSql().replaceAll("\n", "").replaceAll("\\s+", " "));
		
		Class<?> clazz = args[1].getClass();
		
		System.out.print("sql参数:[");
		
		StringBuffer paramStr = new StringBuffer();
		List<ParameterMapping> paramList = boundSql.getParameterMappings();
		for(ParameterMapping param : paramList){
			//判断参数对象是否是基本数据类型
			if(basicTypeSet.contains(boundSql.getParameterObject().getClass().getTypeName())){
				paramStr.append(boundSql.getParameterObject() + ", ");
				continue;
			} 
			//判断是否是Map类型
			else if(this.isImplementsMap(boundSql.getParameterObject())){
				paramStr.append(((Map) boundSql.getParameterObject()).get(param.getProperty()) + ", ");
				continue;
			}
			//处理POJO
			try{
				Method method = clazz.getMethod("get" + toUppercaseFirstChar(param.getProperty()));
				paramStr.append(method.invoke(boundSql.getParameterObject()) + ", ");
			}catch(Exception e){
				paramStr.append(boundSql.getParameterObject() + ", ");
			}

		}
		
		System.out.print(paramStr.length() > 0 ? paramStr.substring(0, paramStr.length() - 2) : "");
		System.out.println("]");
		
		return invocation.proceed();
	}

	@Override
	public Object plugin(Object target) {
		return Plugin.wrap(target, this);
	}

	@Override
	public void setProperties(Properties properties) {
		
	}
	
	/**
	 * 将字符串的首字母转换为大写
	 * 
	 * @param str
	 * @return
	 */
	private String toUppercaseFirstChar(String str){
		char[] c = str.toCharArray();
		c[0] -= 32;
		return new String(c);
	}
	
	/**
	 * 判断对象是否实现了Map接口
	 * @param obj
	 * @return
	 */
	private boolean isImplementsMap(Object obj){
		try{
			Map.class.cast(obj);
			return true;
		}catch(ClassCastException e){
		}
		return false;
	}
}
